;;; basic-functions.el - basic functions.
;;;  
;;; Copyright (C) 2011 Jeffy Du
;;;  
;;; Author: Jeffy Du (cmdxiaoha@163.com)
;;; Create: 2011-12-23 23:36:21
;;; Last Modified: 2011-12-23 23:44:53
;;;  
;;; History:
;;; --------
;;; 2011-12-23  v0.1  Jeffy Du (cmdxiaoha@163.com)
;;;     1. Initial revision.

;; Cut region or lines.
(defun my-kill-region-or-lines ()
  "Smart kill, if `mark-active', call `kill-region', otherwise call `kill-whole-line'."
  (interactive)
  (if mark-active
      (call-interactively 'kill-region)
    (call-interactively 'kill-whole-line))
)

;; Copy lines.
(defun my-copy-lines (&optional number)
  "Copy `number' lines from current line."
  (interactive "p")
  (if (null number)
      (let ((epnd (min (point-max) (1+ (line-end-position)))))
        (copy-region-as-kill (line-beginning-position) end))
    (let ((lineNo))
      (save-excursion
        (if (< number 0)
            (next-line))
        (setq lineNo (line-number-at-pos nil))
        (move-beginning-of-line nil)
        (set-mark-command nil)
        (goto-line (+ number lineNo))
        (call-interactively 'copy-region-as-kill))))
)

;; Copy region or lines.
(defun my-copy-region-or-lines ()
  "Smart copy, if `mark-active', call `copy-region', otherwise call `copy-lines'."
  (interactive)
  (if mark-active (call-interactively 'copy-region-as-kill) (call-interactively 'my-copy-lines))
)

;; Kill to beginning of line.
(defun my-kill-to-begin (&optional arg)
  "Delete characters to line beginning."
  (interactive "P")
  (if (not arg)
      (kill-line 0)
    (copy-region-as-kill-nomark (1+ (line-beginning-position)) (point)))
)

;; Translate case for current char.
(defun my-case-trans ()
  "translate case for current char"
  (interactive)
  (let* ((ochar (char-after (point))) (char ochar))
    (if (and (>= char ?a) (<= char ?z))
        (setq char (upcase char))
      (setq char (downcase char)))
    (if (/= ochar char)
        (save-excursion
          (delete-char 1)
          (insert-char char 1))))
  (call-interactively 'forward-char)
)

;; Comment region or line.
(defun my-comment-region-or-line (&optional arg)
  "if `mark-active', then `comment-region', else comment current line"
  (interactive "P")
  (if mark-active
      (comment-region (region-beginning) (region-end) arg)
    (comment-region (line-beginning-position) (line-end-position)))
)

;; Uncomment region or line.
(defun my-uncomment-region-or-line (&optional arg)
  "if `mark-active', then `uncomment-region', else uncomment current line"
  (interactive "P")
  (if mark-active
      (uncomment-region (region-beginning) (region-end) arg)
    (uncomment-region (line-beginning-position) (line-end-position)))
)

;; Comment & Uncomment for region or line.
(defun my-comment-or-uncomment-region-or-line (&optional arg)
  "if `mark-active', then `comment-or-uncomment-region', else comment-or-uncomment-line."
  (interactive "P")
  (if mark-active
      (comment-or-uncomment-region (region-beginning) (region-end) arg)
    (comment-or-uncomment-region (line-beginning-position) (line-end-position)))
)

;; Goto matched parentheses.
(defun my-goto-paren ()
  "Jump to matched paren."
  (interactive)
  (cond
   ((looking-at "[ \t]*[[({]") (forward-sexp) (backward-char))
   ((or (looking-at "[])}]") (looking-back "[])}][ \t]*"))
    (if (< (point) (point-max)) (forward-char)) (backward-sexp))
   (t (if (re-search-forward "[[({]" nil t -1)
          (message "Jump back to the nearest parentheses.")
        (message "Cann't find matched parentheses."))))
)

;; Search current word on cursor.
(defun my-isearch-forword-cur-word (&optional backward)
  "`isearch-forward' current word."
  (interactive "P")
  (let ((fun (if backward 'isearch-backward 'isearch-forward)))
    (let ((cur-word (current-word)))
      (if (not cur-word)
          (message "No word under cursor.")
        (call-interactively fun)
        (isearch-yank-string cur-word))))
)

;; Find char forward & backward.
(defun my-goto-char (n char)
  "Move forward to Nth occurence of CHAR. If N is negative, then move backward."
  (interactive "p\ncGoto char: ")
  (search-forward (string char) nil nil n)
  (while (char-equal (read-char) char)
    (search-forward (string char) nil nil n))
  (setq unread-command-events (list last-input-event))
)

;; Mark something at point.
(defun my-mark-something-at-point ()
  (interactive)
  (let* ((from (point))
         (a (mouse-start-end from from 1))
         (start (car a))
         (end (cadr a))
         (goto-point (if (= from start)
                         end
                       start)))
    (if (eq last-command 'my-mark-something-at-point)
        (progn
          (goto-char (mark-marker))
          (set-marker (mark-marker) from))
      (push-mark (if (= goto-point start) end start) nil t)
      (when (and (interactive-p) (null transient-mark-mode))
        (goto-char (mark-marker))
        (sit-for 0 500 nil))
      (goto-char goto-point)))
)

;; Set mark.
(defun my-point-to-register ()
  "Store cursor-position in a register.
Use my-jump-to-register to jump back to the stored position."
  (interactive)
  (setq zmacs-region-stays t)
  (point-to-register 8)
)

;; Jump to mark.
(defun my-jump-to-register ()
  "Store cursor-position in a register, and jump back to the last stored position."
  (interactive)
  (setq zmacs-region-stays t)
  (let ((tmp (point-marker)))
    (jump-to-register 8)
    (set-register 8 tmp))
)